package kim.artemis.rpc.core.protocol.server;

import cn.hutool.core.util.StrUtil;
import kim.artemis.rpc.core.common.exception.ArtemisException;
import kim.artemis.rpc.core.model.ArtemisRpcRequest;
import kim.artemis.rpc.core.model.ArtemisRpcResponse;
import kim.artemis.rpc.core.registry.ServiceRegistry;
import kim.artemis.rpc.core.protocol.serializer.ArtemisSerializer;
import kim.artemis.rpc.core.util.ArtemisUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务端
 * @author Wq.
 */
@Slf4j
public class ArtemisRpcServer {

    /**
     * 服务注册地址
     */
    private String address;

    /**
     * 端口
     */
    @Getter
    private int port;

    /**
     * 令牌
     */
    @Getter
    private String accessToken;

    /**
     * 序列化
     */
    @Getter
    private ArtemisSerializer serializer;

    /**
     * 注册中心
     */
    private Class<? extends ServiceRegistry> registryCenter;

    /**
     * 服务注册
     */
    private ServiceRegistry serviceRegistry;

    /**
     * 服务仓库
     */
    @Getter
    private Map<String, Object> serviceRepository = new HashMap<>();

    /**
     * 服务端线程
     */
    private ArtemisRpcServerThread artemisRpcServerThread;

    /**
     * 启动线程
     */
    public void start(String address, int port, String accessToken, ArtemisSerializer serializer, Class<? extends ServiceRegistry> registryCenter) {
        this.address = address;
        this.port = port;
        this.accessToken = accessToken;
        this.serializer = serializer;
        this.registryCenter = registryCenter;

        if (0 >= this.port) {
            this.port = 8731;
        }

        if (null == this.serializer) {
           throw new ArtemisException("artemis rpc, server serializer missing.");
        }

        if (null != this.registryCenter) {
            try {
                this.serviceRegistry = registryCenter.newInstance();
                this.serviceRegistry.start(address);
            } catch (Exception e) {
                throw new ArtemisException(e);
            }
        }

        artemisRpcServerThread = new ArtemisRpcServerThread();
        artemisRpcServerThread.start(this);

        // 格式化socketAddress
        address = ArtemisUtils.networkAddressPort(port);

        // 注册服务
        this.serviceRegistry.register(serviceRepository.keySet(), address);
    }

    /**
     * 停止线程
     * @throws Exception
     */
    public void stop () throws Exception {
        artemisRpcServerThread.stop();
    }


    /**
     * 推送服务
     * @param name
     * @param version
     * @param serviceBean
     */
    public void pushService (String name, String version, Object serviceBean) {
        String serviceKey = ArtemisUtils.serviceKey(name, version);
        serviceRepository.put(serviceKey, serviceBean);
        log.info(">>>>>>> artemis rpc, server factory push service success. serviceKey = {}, serviceBean = {}", serviceKey, serviceBean.getClass());
    }

    /**
     * 调用程序
     * @param artemisRpcRequest
     * @return
     */
    public ArtemisRpcResponse invoker (ArtemisRpcRequest artemisRpcRequest) {

        ArtemisRpcResponse artemisRpcResponse = new ArtemisRpcResponse();
        artemisRpcResponse.setArtemisId(artemisRpcRequest.getArtemisId());

        // 匹配服务
        String serviceKey = ArtemisUtils.serviceKey(artemisRpcRequest.getClassName(), artemisRpcRequest.getVersion());
        Object serviceBean = serviceRepository.get(serviceKey);

        // 未匹配到服务
        if (null == serviceBean) {
            artemisRpcResponse.setException("The serviceKey [" + serviceKey + "] is not found.");
            return artemisRpcResponse;
        }

        // 请求过期 过期时间 60 秒
        if (System.currentTimeMillis() - artemisRpcRequest.getTimestamp() > 60 * 1000) {
            artemisRpcResponse.setException("The request has expired. artemisId: " + artemisRpcRequest.getArtemisId());
            return artemisRpcResponse;
        }

        // 访问令牌错误
        if (StrUtil.isNotBlank(accessToken) && !accessToken.trim().equals(artemisRpcRequest.getAccessToken())) {
            artemisRpcResponse.setException("The access token [" + artemisRpcRequest.getAccessToken() + "] error.");
            return artemisRpcResponse;
        }

        try {
            // 调用方法
            Class<?> serviceClass = serviceBean.getClass();
            String methodName = artemisRpcRequest.getMethodName();
            Class<?>[] parameterTypes = artemisRpcRequest.getParameterTypes();
            Object[] parameters = artemisRpcRequest.getParameters();
            Method method = serviceClass.getMethod(methodName, parameterTypes);
            method.setAccessible(true);
            Object result = method.invoke(serviceBean, parameters);
            // 响应结果
            artemisRpcResponse.setResult(result);
        } catch (Exception e) {
            log.error(">>>>>>> artemis rpc, server invokes service exception. ", e);
            artemisRpcResponse.setException(e.getLocalizedMessage());
        }
        return artemisRpcResponse;
    }


}
